﻿using System;
using System.Collections.Generic;
using System.Text;
using Core.Model.Data.Generics;
using Core.Parser.ASN1Parser.Nodes;
using Core.Model.Data.Type;
using Core.Model;
using Core.Exceptions;

namespace Core.Parser.ASN1Parser.Builders
{
    internal class GenericVariableBuilder
    {
        internal static Generic Build(TaggedNode node, Group group)
        {
            Generic ret = null;

            switch (node.Tag)
            {
                case ASN1ContextCodes.C_NEW_GENERIC_BOOLEAN:
                    ret = BuildGenericBoolean(node.First, group); 
                    break;

                case ASN1ContextCodes.C_NEW_GENERIC_INTEGER:
                    ret = BuildGenericInteger(node.First, group);
                    break;

                case ASN1ContextCodes.C_NEW_GENERIC_OCTETSTRING:
                    ret = BuildGenericOctetString(node.First, group);
                    break;

                case ASN1ContextCodes.C_NEW_GENERIC_OBJECT_REF:
                    ret = BuildGenericObjectRef(node.First, group);
                    break;

                case ASN1ContextCodes.C_NEW_GENERIC_CONTENT_REF:
                    ret = BuildGenericContentRef(node.First, group);
                    break;

            }

            return ret;
        }

        internal static GenericBoolean BuildGenericBoolean(ASN1Node node, Group group)
        {
            GenericBoolean genericBoolean;
            TaggedNode e;

            if (node is TaggedNode && (e = (TaggedNode)node).Tag == ASN1ContextCodes.C_INDIRECTREFERENCE)
            {
                genericBoolean = new GenericBoolean(ObjectRefBuilder.Build(e.First, group));
            }
            else if (node is BoolNode)
            {
                genericBoolean = new GenericBoolean(node.BoolValue);
            }
            else 
                throw new OpenMhegException("Wrong node");

            return genericBoolean;
        }

        internal static GenericInteger BuildGenericInteger(ASN1Node node, Group group)
        {
            GenericInteger genericInteger;
            TaggedNode e;

            if (node is TaggedNode && (e = (TaggedNode)node).Tag == ASN1ContextCodes.C_INDIRECTREFERENCE)
            {
                genericInteger = new GenericInteger(ObjectRefBuilder.Build(e.First, group));
            }
            else if (node is IntNode)
            {
                genericInteger = new GenericInteger(node.IntValue);
            }
            else
                throw new OpenMhegException("Wrong node");

            return genericInteger;
        }

        internal static GenericOctetString BuildGenericOctetString(ASN1Node node, Group group)
        {
            GenericOctetString genericOctetString;
            TaggedNode e;

            if (node is TaggedNode && (e = (TaggedNode)node).Tag == ASN1ContextCodes.C_INDIRECTREFERENCE)
            {
                genericOctetString = new GenericOctetString(ObjectRefBuilder.Build(e.First,group));
            }
            else if (node is OctetStringNode)
            {
                genericOctetString = new GenericOctetString(node.StringValue);
            }
            else
                throw new OpenMhegException("Wrong node");

            return genericOctetString;
        }
                
        internal static GenericObjectRef BuildGenericObjectRef(ASN1Node node, Group group)
        {
            GenericObjectRef genericObjectRef;
            TaggedNode e;

              //Indirect
             if (node is TaggedNode && (e = (TaggedNode)node).Tag == ASN1ContextCodes.C_INDIRECTREFERENCE)
                genericObjectRef = new GenericObjectRef(null, ObjectRefBuilder.Build(e.First, group));
           
            //Direct
            else if (node is SequenceNode || node is IntNode)
                genericObjectRef =  new GenericObjectRef(ObjectRefBuilder.Build(node, group), null);
          
            else 
                throw new OpenMhegException("Wrong node");

            return genericObjectRef;
        }

        internal static GenericContentRef BuildGenericContentRef(ASN1Node node, Group group)
        {
            GenericContentRef genericContentRef = null;
            TaggedNode e;

            if (node is TaggedNode && (e = (TaggedNode)node).Tag == ASN1ContextCodes.C_INDIRECTREFERENCE)
                genericContentRef = new GenericContentRef(ObjectRefBuilder.Build(e.First, group));

            else if (node is TaggedNode && (e = (TaggedNode)node).Tag == ASN1ContextCodes.C_CONTENT_REFERENCE)
            {
                throw new Exception("Delete me");
                genericContentRef = new GenericContentRef(ContentRefBuilder.BuildContentRef((SequenceNode)e.First, group));
            }
            else if (node is SequenceNode && ((SequenceNode)node).First is TaggedNode && (e = (TaggedNode)((SequenceNode)node).First).Tag == ASN1ContextCodes.C_CONTENT_REFERENCE)
                genericContentRef = new GenericContentRef(ContentRefBuilder.BuildContentRef((TaggedNode)((SequenceNode)node).First, group));
            else if (node is SequenceNode)
            {
                if (((SequenceNode)node).First is TaggedNode && (e = (TaggedNode)((SequenceNode)node).First).Tag == ASN1ContextCodes.C_INDIRECTREFERENCE)
                    genericContentRef = new GenericContentRef(ObjectRefBuilder.Build(e.First, group));

                //              genericContentRef = new GenericContentRef(ContentRefBuilder.BuildContentRef((SequenceNode)node, group));
            }
            else
                throw new OpenMhegException("Wrong node");

            if (genericContentRef == null) throw new NullReferenceException();

            var seq = node as SequenceNode;

            if (seq.Size > 1)
            {

                if ((e = seq[ASN1ContextCodes.C_NEW_CONTENT_SIZE]) != null)
                    if (e.First is IntNode)
                        genericContentRef.Value.ContentSize = e.First.IntValue;


                if (seq.Size > 2)
                {
                    if ((e = seq[ASN1ContextCodes.C_NEW_CONTENT_CACHE_PRIO]) != null)
                        if (e.First is IntNode)
                            genericContentRef.Value.ContentCachePriority = e.First.IntValue;
                }
            }
         

            return genericContentRef;

        }


    }
}
